home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / x+opengl / glxdino.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  13KB  |  371 lines

  1. /* $Revision: 1.2 $ */
  2. /* compile: cc -o glxdino glxdino.c -lGLU -lGL -lXmu -lX11 */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <math.h>        /* for cos(), sin(), and sqrt() */
  7. #include <GL/glx.h>        /* this includes X and gl.h headers */
  8. #include <GL/glu.h>        /* gluPerspective(), gluLookAt(), GLU polygon
  9.                  * tesselator */
  10. #include <X11/Xatom.h>        /* for XA_RGB_DEFAULT_MAP atom */
  11. #include <X11/Xmu/StdCmap.h>    /* for XmuLookupStandardColormap() */
  12. #include <X11/keysym.h>        /* for XK_Escape keysym */
  13.  
  14. typedef enum {
  15.     RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
  16.     LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
  17. }               displayLists;
  18.  
  19. Display *dpy;
  20. Window win;
  21. GLfloat angle = -150;    /* in degrees */
  22. GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
  23. int W = 300, H = 300;
  24. XSizeHints sizeHints = {0};
  25. GLdouble bodyWidth = 2.0;
  26. int configuration[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, None};
  27. GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
  28.     {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
  29.     {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
  30.     {1, 2} };
  31. GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
  32.     {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
  33.     {13, 9}, {11, 11}, {9, 11} };
  34. GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
  35.     {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
  36. GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
  37.     {9.6, 15.25}, {9, 15.25} };
  38. GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
  39. GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
  40. GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
  41. GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0};  /* red-tinted */
  42. GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
  43. GC gc;
  44. XGCValues gcvals;
  45.  
  46. void
  47. fatalError(char *message)
  48. {
  49.     fprintf(stderr, "glxdino: %s\n", message);
  50.     exit(1);
  51. }
  52.  
  53. Colormap
  54. getColormap(XVisualInfo * vi)
  55. {
  56.     Status          status;
  57.     XStandardColormap *standardCmaps;
  58.     Colormap        cmap;
  59.     int             i, numCmaps;
  60.  
  61.     /* be lazy; using DirectColor too involved for this example */
  62.     if (vi->class != TrueColor)
  63.         fatalError("no support for non-TrueColor visual");
  64.     /* if no standard colormap but TrueColor, just make an unshared one */
  65.     status = XmuLookupStandardColormap(dpy, vi->screen, vi->visualid,
  66.         vi->depth, XA_RGB_DEFAULT_MAP, /* replace */ False, /* retain */ True);
  67.     if (status == 1) {
  68.     status = XGetRGBColormaps(dpy, RootWindow(dpy, vi->screen),
  69.                  &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP);
  70.     if (status == 1)
  71.         for (i = 0; i < numCmaps; i++)
  72.         if (standardCmaps[i].visualid == vi->visualid) {
  73.             cmap = standardCmaps[i].colormap;
  74.             XFree(standardCmaps);
  75.             return cmap;
  76.         }
  77.     }
  78.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
  79.         vi->visual, AllocNone);
  80.     return cmap;
  81. }
  82.  
  83. void
  84. extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
  85.     GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
  86. {
  87.     static GLUtriangulatorObj *tobj = NULL;
  88.     GLdouble        vertex[3], dx, dy, len;
  89.     int             i;
  90.     int             count = dataSize / (2 * sizeof(GLfloat));
  91.  
  92.     if (tobj == NULL) {
  93.     tobj = gluNewTess();    /* create and initialize a GLU polygon
  94.                  * tesselation object */
  95.     gluTessCallback(tobj, GLU_BEGIN, glBegin);
  96.     gluTessCallback(tobj, GLU_VERTEX, glVertex2fv);    /* semi-tricky */
  97.     gluTessCallback(tobj, GLU_END, glEnd);
  98.     }
  99.     glNewList(side, GL_COMPILE);
  100.         glShadeModel(GL_SMOOTH); /* smooth minimizes seeing tessellation */
  101.         gluBeginPolygon(tobj);
  102.             for (i = 0; i < count; i++) {
  103.             vertex[0] = data[i][0];
  104.             vertex[1] = data[i][1];
  105.             vertex[2] = 0;
  106.             gluTessVertex(tobj, vertex, &data[i]);
  107.             }
  108.         gluEndPolygon(tobj);
  109.     glEndList();
  110.     glNewList(edge, GL_COMPILE);
  111.         glShadeModel(GL_FLAT);    /* flat shade keeps angular hands from being
  112.                  * "smoothed" */
  113.         glBegin(GL_QUAD_STRIP);
  114.         for (i = 0; i <= count; i++) {
  115.         /* mod function handles closing the edge */
  116.         glVertex3f(data[i % count][0], data[i % count][1], 0.0);
  117.         glVertex3f(data[i % count][0], data[i % count][1], thickness);
  118.         /* Calculate a unit normal by dividing by Euclidean distance. We
  119.          * could be lazy and use glEnable(GL_NORMALIZE) so we could pass in
  120.          * arbitrary normals for a very slight performance hit. */
  121.         dx = data[(i + 1) % count][1] - data[i % count][1];
  122.         dy = data[i % count][0] - data[(i + 1) % count][0];
  123.         len = sqrt(dx * dx + dy * dy);
  124.         glNormal3f(dx / len, dy / len, 0.0);
  125.         }
  126.         glEnd();
  127.     glEndList();
  128.     glNewList(whole, GL_COMPILE);
  129.         glFrontFace(GL_CW);
  130.         glCallList(edge);
  131.         glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
  132.         glCallList(side);
  133.         glPushMatrix();
  134.             glTranslatef(0.0, 0.0, thickness);
  135.             glFrontFace(GL_CCW);
  136.             glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
  137.             glCallList(side);
  138.         glPopMatrix();
  139.     glEndList();
  140. }
  141.  
  142. void
  143. makeDinosaur(void)
  144. {
  145.     GLfloat         bodyWidth = 3.0;
  146.  
  147.     extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
  148.         BODY_SIDE, BODY_EDGE, BODY_WHOLE);
  149.     extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
  150.         ARM_SIDE, ARM_EDGE, ARM_WHOLE);
  151.     extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
  152.         LEG_SIDE, LEG_EDGE, LEG_WHOLE);
  153.     extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
  154.         EYE_SIDE, EYE_EDGE, EYE_WHOLE);
  155.     glNewList(DINOSAUR, GL_COMPILE);
  156.         glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
  157.         glCallList(BODY_WHOLE);
  158.         glPushMatrix();
  159.             glTranslatef(0.0, 0.0, bodyWidth);
  160.             glCallList(ARM_WHOLE);
  161.             glCallList(LEG_WHOLE);
  162.             glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
  163.             glCallList(ARM_WHOLE);
  164.             glTranslatef(0.0, 0.0, -bodyWidth / 4);
  165.             glCallList(LEG_WHOLE);
  166.             glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
  167.             glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
  168.             glCallList(EYE_WHOLE);
  169.         glPopMatrix();
  170.     glEndList();
  171. }
  172.  
  173. void
  174. redraw(void)
  175. {
  176. static int x = 0;
  177.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  178.     glCallList(DINOSAUR);
  179.     if (doubleBuffer)
  180.     glXSwapBuffers(dpy, win);    /* buffer swap does implicit glFlush */
  181.     else glFlush();        /* explicit flush for single buffered case */
  182. #if 1
  183.     XDrawLine(dpy, win, gc, 10+x, 10, 40+x, 40);
  184.     x+=8;
  185.     XSync(dpy, 0);
  186. #endif
  187. }
  188.  
  189. void
  190. main(int argc, char **argv)
  191. {
  192.     XVisualInfo    *vi;
  193.     Colormap        cmap;
  194.     XSetWindowAttributes swa;
  195.     XWMHints       *wmHints;
  196.     Atom            wmDeleteWindow;
  197.     GLXContext      cx;
  198.     XEvent          event;
  199.     KeySym          ks;
  200.     GLboolean       needRedraw = GL_FALSE, recalcModelView = GL_TRUE;
  201.     char           *display = NULL, *geometry = NULL;
  202.     int             flags, x, y, width, height, lastX, i;
  203.  
  204.     /*** (1) process normal X command line arguments ***/
  205.     for (i = 1; i < argc; i++) {
  206.     if (!strcmp(argv[i], "-geometry")) {
  207.         if (++i >= argc)
  208.         fatalError("follow -geometry option with geometry parameter");
  209.         geometry = argv[i];
  210.     } else if (!strcmp(argv[i], "-display")) {
  211.         if (++i >= argc)
  212.         fatalError("follow -display option with display parameter");
  213.         display = argv[i];
  214.     } else if (!strcmp(argv[i], "-iconic")) iconic = GL_TRUE;
  215.     else if (!strcmp(argv[i], "-keepaspect")) keepAspect = GL_TRUE;
  216.     else if (!strcmp(argv[i], "-single")) doubleBuffer = GL_FALSE;
  217.     else fatalError("bad option");
  218.     }
  219.  
  220.     /*** (2) open a connection to the X server ***/
  221.     dpy = XOpenDisplay(display);
  222.     if (dpy == NULL) fatalError("could not open display");
  223.  
  224.     /*** (3) make sure OpenGL's GLX extension supported ***/
  225.     if (!glXQueryExtension(dpy, NULL, NULL))
  226.     fatalError("X server has no OpenGL GLX extension");
  227.  
  228.     /*** (4) find an appropriate visual and a colormap for it ***/
  229.     /* find an OpenGL-capable RGB visual with depth buffer */
  230.     if (!doubleBuffer) goto SingleBufferOverride;
  231.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), configuration);
  232.     if (vi == NULL) {
  233.       SingleBufferOverride:
  234.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), &configuration[1]);
  235.     if (vi == NULL)
  236.         fatalError("no appropriate RGB visual with depth buffer");
  237.     doubleBuffer = GL_FALSE;
  238.     }
  239.     cmap = getColormap(vi);
  240.  
  241.     /*** (5) create an OpenGL rendering context  ***/
  242.     /* create an OpenGL rendering context */
  243.     cx = glXCreateContext(dpy, vi, /* no sharing of display lists */ NULL,
  244.                /* direct rendering if possible */ GL_TRUE);
  245.     if (cx == NULL) fatalError("could not create rendering context");
  246.  
  247.     /*** (6) create an X window with selected visual and right properties ***/
  248.     flags = XParseGeometry(geometry, &x, &y,
  249.     (unsigned int *) &width, (unsigned int *) &height);
  250.     if (WidthValue & flags) {
  251.     sizeHints.flags |= USSize;
  252.     sizeHints.width = width;
  253.     W = width;
  254.     }
  255.     if (HeightValue & flags) {
  256.     sizeHints.flags |= USSize;
  257.     sizeHints.height = height;
  258.     H = height;
  259.     }
  260.     if (XValue & flags) {
  261.     if (XNegative & flags)
  262.         x = DisplayWidth(dpy, DefaultScreen(dpy)) + x - sizeHints.width;
  263.     sizeHints.flags |= USPosition;
  264.     sizeHints.x = x;
  265.     }
  266.     if (YValue & flags) {
  267.     if (YNegative & flags)
  268.         y = DisplayHeight(dpy, DefaultScreen(dpy)) + y - sizeHints.height;
  269.     sizeHints.flags |= USPosition;
  270.     sizeHints.y = y;
  271.     }
  272.     if (keepAspect) {
  273.     sizeHints.flags |= PAspect;
  274.     sizeHints.min_aspect.x = sizeHints.max_aspect.x = W;
  275.     sizeHints.min_aspect.y = sizeHints.max_aspect.y = H;
  276.     }
  277.     swa.colormap = cmap;
  278.     swa.border_pixel = 0;
  279.     swa.event_mask = ExposureMask | StructureNotifyMask |
  280.     ButtonPressMask | Button1MotionMask | KeyPressMask;
  281.     win = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
  282.                         sizeHints.x, sizeHints.y, W, H,
  283.             0, vi->depth, InputOutput, vi->visual,
  284.             CWBorderPixel | CWColormap | CWEventMask, &swa);
  285.     gcvals.line_width = 5;
  286.     gcvals.foreground = 45;
  287.     gc = XCreateGC(dpy, win, GCForeground|GCLineWidth, &gcvals);
  288.     XSetStandardProperties(dpy, win, "OpenGLosaurus", "glxdino",
  289.         None, argv, argc, &sizeHints);
  290.     wmHints = XAllocWMHints();
  291.     wmHints->initial_state = iconic ? IconicState : NormalState;
  292.     wmHints->flags = StateHint;
  293.     XSetWMHints(dpy, win, wmHints);
  294.     wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  295.     XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
  296.  
  297.     /*** (7) bind the rendering context to the window ***/
  298.     glXMakeCurrent(dpy, win, cx);
  299.  
  300.     /*** (8) make the desired display lists ***/
  301.     makeDinosaur();
  302.  
  303.     /*** (9) configure the OpenGL context for rendering ***/
  304.     glEnable(GL_CULL_FACE);    /* ~50% better perfomance than no back-face
  305.                  * culling on Entry Indigo */
  306.     glEnable(GL_DEPTH_TEST);    /* enable depth buffering */
  307.     glEnable(GL_LIGHTING);    /* enable lighting */
  308.     glMatrixMode(GL_PROJECTION);/* set up projection transform */
  309.     gluPerspective( /* field of view in degree */ 40.0, /* aspect ratio */ 1.0,
  310.             /* Z near */ 1.0, /* Z far */ 40.0);
  311.     glMatrixMode(GL_MODELVIEW);    /* now change to modelview */
  312.     gluLookAt(0.0, 0.0, 30.0,    /* eye is at (0,0,30) */
  313.           0.0, 0.0, 0.0,    /* center is at (0,0,0) */
  314.           0.0, 1.0, 0.);    /* up is in postivie Y direction */
  315.     glPushMatrix();        /* dummy push so we can pop on model recalc */
  316.     glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  317.     glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
  318.     glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
  319.     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
  320.     glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
  321.     glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
  322.     glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
  323.     glEnable(GL_LIGHT0);
  324.     glEnable(GL_LIGHT1);    /* enable both lights */
  325.  
  326.     /*** (10) request the X window to be displayed on the screen ***/
  327.     XMapWindow(dpy, win);
  328.  
  329.     /*** (11) dispatch X events ***/
  330.     while (1) {
  331.     do {
  332.         XNextEvent(dpy, &event);
  333.         switch (event.type) {
  334.         case ConfigureNotify:
  335.         glViewport(0, 0,
  336.             event.xconfigure.width, event.xconfigure.height);
  337.         /* fall through... */
  338.         case Expose:
  339.         needRedraw = GL_TRUE;
  340.         break;
  341.         case MotionNotify:
  342.         recalcModelView = GL_TRUE;
  343.         angle -= (lastX - event.xmotion.x);
  344.         case ButtonPress:
  345.         lastX = event.xbutton.x;
  346.         break;
  347.         case KeyPress:
  348.         ks = XLookupKeysym((XKeyEvent *) & event, 0);
  349.         if (ks == XK_Escape) exit(0);
  350.         break;
  351.         case ClientMessage:
  352.         if (event.xclient.data.l[0] == wmDeleteWindow) exit(0);
  353.         break;
  354.         }
  355.     } while (XPending(dpy));/* loop to compress events */
  356.     if (recalcModelView) {
  357.         glPopMatrix();    /* pop old rotated matrix (or dummy matrix if
  358.                  * first time) */
  359.         glPushMatrix();
  360.         glRotatef(angle, 0.0, 1.0, 0.0);
  361.         glTranslatef(-8, -8, -bodyWidth / 2);
  362.         recalcModelView = GL_FALSE;
  363.         needRedraw = GL_TRUE;
  364.     }
  365.     if (needRedraw) {
  366.         redraw();
  367.         needRedraw = GL_FALSE;
  368.     }
  369.     }
  370. }
  371.